#pragma once
#include <iostream>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define Screen 1
#define Onefile 2
#define Classfile 3

#define INFO 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4

#define SIZE 1024
#define LogFile "log.txt"

class Log{
public:
    // 构造函数      
    // 注意如果路径中的目录不存在，需要先手动创建目录
    Log(int printMethod = Screen, std::string path = "./log/")
    :_printMethod(printMethod),_path(path)
    {}

    // 设置打印方式
    void Enable(int Method){
        _printMethod = Method;
    }

    // 日志等级
    std::string LevelToString(int level){
        switch(level){
            case INFO:
                return "INFO";
            case Debug:
                return "Debug";
            case Warning:
                return "Warning";
            case Error:
                return "Error";
            case Fatal:
                return "Fatal";
            default:
                return "NONE";
        }
    }

    // 单个文件写入
    void OneFilePrint(const std::string &filename, const std::string &logtxt){
        // 文件名前加上对应的路径信息
        std::string _filename = _path + filename;
        int fd = open(_filename.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
        if(fd < 0){
            return;
        }
        write(fd, logtxt.c_str(), logtxt.size());
        close(fd);
    }

    // 分类文件写入
    void ClassFilePrint(int level, const std::string &logtxt){
        // 根据日志等级添加对应的文件后缀
        std::string filename = LogFile;
        filename += ".";
        filename += LevelToString(level);
        OneFilePrint(filename, logtxt);
    }

    void PrintLog(int level, const std::string &logtxt){
        switch(_printMethod){
            case Screen:
                std::cout << logtxt << std::endl;
                break;
            case Onefile:
                OneFilePrint(LogFile, logtxt);
                break;
            case Classfile:
                ClassFilePrint(level, logtxt);
                break;
            default:
                break;
        }
    }

    void operator()(int level, const char *format, ...){
        time_t t = time(nullptr);                 // 获取时间戳
        struct tm *ctime = localtime(&t);        

        // 日志默认格式--左半部分
        char leftbuffer[SIZE];
        snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d-%d-%d]", LevelToString(level).c_str(),
                 ctime->tm_year+1900, ctime->tm_mon+1, ctime->tm_mday,
                 ctime->tm_hour, ctime->tm_min, ctime->tm_sec);
        
        // 日志自定义格式--右半部分
        va_list s;                    // 定义一个一个变量用来获取可变参数列表
        va_start(s, format);          // 获取可变参数的第一个指针
        char rightbuffer[SIZE];
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
        va_end(s);

        // 日志内容左右部分合并
        char logtxt[SIZE * 2];
        snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);

        PrintLog(level, logtxt);
        //std::cout << logtxt << std::endl;
    }

    ~Log(){}
private:
    int _printMethod;
    std::string _path;
};

Log log;
